package com.crawler.base;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class CrawlerBase {

	public static final int DefaultPoliteness = 10;
	public static final int DefaultMaxPages = 20;
	public static final String DefaultSeedPage = "http://www.theage.com.au/digital-life/mobiles/Mobiles/iPhone";
	
//	private URL seedURL;
	private IOutputInterface mOutput;
	private Map<String, Page> mMapRelPages;
	private Map<String, Page> mMapUnRelPages;
	private List<String> mListFeature;
	private List<String> mLockPool;
	
	public CrawlerBase(IOutputInterface Output, ICrawlerEventHandler crawlerEvent)
	{
		mOutput = Output;
		mMapRelPages = new HashMap<String, Page>();
		mMapUnRelPages = new HashMap<String, Page>();
		mListFeature = new ArrayList<String>();
		mLockPool = new ArrayList<String>();
	}

	public void Init()
	{
		mOutput.OutputPrint("Crawler Init....");
		mMapRelPages.clear();
		mMapUnRelPages.clear();
		LoadFeatureList();
	}

	public void StartSmartCrawler(int nPoliteness, int nMaxPages, String strURL, ICrawlerEventHandler handler)
	{
		Thread t = new CrawlerWorker(this, mOutput, nPoliteness, nMaxPages, strURL, handler, true, new String(""), true);
		t.start();
	}
	
	public void StartCrawler(int nPoliteness, int nMaxPages, String strURL, ICrawlerEventHandler handler, boolean bIsRel)
	{
		try {
			URL url = new URL(strURL);
			int nIdx = mLockPool.indexOf(url.getHost());
			
			String strLock = "";
			if(nIdx >= 0)
			{
				strLock = mLockPool.get(nIdx);
			}
			else
			{
				strLock = url.getHost();
				mLockPool.add(strLock);
			}
			Thread t = new CrawlerWorker(this, mOutput, nPoliteness, nMaxPages, strURL, handler, bIsRel, strLock, false);
			t.start();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void AddPageToMap(Page page, boolean bIsRel)
	{
		mOutput.OutputPrint(String.format("Adding new page [%s]-[%d]", page.GetTitle(), bIsRel?1:0));
		if(bIsRel)
			mMapRelPages.put(page.GetPageURL(), page);
		else
			mMapUnRelPages.put(page.GetPageURL(), page);
	}
	
	public Page GetPage(String strTitle, boolean bIsRel)
	{
		if(bIsRel && mMapRelPages.containsKey(strTitle))
			return mMapRelPages.get(strTitle);
		else if(!bIsRel && mMapUnRelPages.containsKey(strTitle))
			return mMapUnRelPages.get(strTitle);
		
		return null;
	}
	
	public void MovePageToNextGroup(String strTitle, boolean bSrcIsRel)
	{
		if(bSrcIsRel && mMapRelPages.containsKey(strTitle))
		{
			mMapUnRelPages.put(strTitle, mMapRelPages.get(strTitle));
			mMapRelPages.remove(strTitle);
		}
		else if(!bSrcIsRel && mMapUnRelPages.containsKey(strTitle))
		{
			mMapRelPages.put(strTitle, mMapUnRelPages.get(strTitle));
			mMapUnRelPages.remove(strTitle);
		}
	}
	
	public void LoadFeatureList()
	{
		mListFeature.clear();
		try {
			BufferedReader reader = new BufferedReader(new FileReader("feature.txt"));
			String line = reader.readLine();
			while(line != null)
			{
				mListFeature.add(line);
				line = reader.readLine();
			}
			reader.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public boolean AddFeature(String strFeature)
	{
		if(!mListFeature.contains(strFeature))
		{
			mOutput.OutputPrint(String.format("Adding Feature [%s]", strFeature));
			mListFeature.add(strFeature);
			return true;
		}
		else
		{
			mOutput.OutputPrint(String.format("Feature [%s] already exist", strFeature));
			return false;
		}
	}
	
	public boolean RemoveFeature(String strFeature)
	{
		mOutput.OutputPrint(String.format("Remove feature [%s]", strFeature));
		return mListFeature.remove(strFeature);
	}
	
	public List<String> GetFeatureList()
	{
		return mListFeature;
	}
	
	public void GenerateARFF(String strFilePath)
	{
		SaveFeatureFile();
		
		try {
			PrintWriter out = new PrintWriter(strFilePath);
			out.println("@relation 'mobilepages'");
			for( String feature : mListFeature)
			{
				out.println(String.format("@attribute %s real", feature));
			}
			out.println(String.format("@attribute IsMobile {Y, N}"));
			out.println("@data");
			for(Page page : mMapRelPages.values())
			{
				String strTemp = page.GetFeatureSetAsString();
				strTemp += "Y";
				out.println(strTemp);
			}
			for(Page page : mMapUnRelPages.values())
			{
				String strTemp = page.GetFeatureSetAsString();
				strTemp += "N";
				out.println(strTemp);
			}
			out.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void ProcessAllPages()
	{
		for(Page page : mMapRelPages.values())
		{
			page.ResetFeatureSet(mListFeature);
			page.ProcessPage();
		}
		
		for(Page page : mMapUnRelPages.values())
		{
			page.ResetFeatureSet(mListFeature);
			page.ProcessPage();
		}
	}
	
	public Map<String, Page> GetPageSet(boolean bIsRel)
	{
		if(bIsRel)
			return mMapRelPages;
		else
			return mMapUnRelPages;
	}
	
	private void SaveFeatureFile()
	{
		try {
			PrintWriter out = new PrintWriter("feature.txt");
			for( String feature : mListFeature)
			{
				out.println(feature);
			}
			out.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}
